package br.com.news.activity.json;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.util.Log;
import br.com.news.exception.ConnectionException;
import br.com.news.util.Constantes;

/**
 * Classe criada para realizar as conexões com o servidor.
 * 
 * @author Jefferson
 * @since 22/03/2013
 */
public class Http {
	
	/**
	 * Enum com os tipo de requisição para o web service.
	 * 
	 * @author Jefferson
	 * @since 25/03/2013
	 */
	public enum ConnectionType {
		GET, POST;
	}

	/**
	 * Realizar a conexão com o serviço
	 * 
	 * @param ConnectionType
	 * @param url
	 * @param Map<String, String>
	 * @return Reader
	 * @throws ConnectionException
	 */
	public static Reader connection(ConnectionType type, String url, Map<String, String> parameters) throws ConnectionException {
		if (type.equals(ConnectionType.GET)) {
			return doGet(url);
		} else {
			return doPost(url, parameters);
		}
	}

	/**
	 * Realiza a chamada da url como GET
	 * 
	 * @param url
	 * @return Reader
	 * @throws ConnectionException
	 */
	private static Reader doGet(String url) throws ConnectionException {
		try {
			HttpResponse httpResponse = requestGet(url);
			if (checkCodeReturn(httpResponse, url)) {
				HttpEntity httpEntity = httpResponse.getEntity();
				return new InputStreamReader(httpEntity.getContent());
			} else {
				throw new ConnectionException("<GenericHttp.doGet> Não foi possivel conectar ao servidor.");
			}
		} catch (IOException e) {
			Log.e(Constantes.LOG, e.getMessage(), e);
			throw new ConnectionException(String.format("<GenericHttp> Falha ao realizar uma requisição Get para url: %s", url), e);
		}
	}

	/**
	 * Realiza a chamada da url como Post
	 * 
	 * @param url
	 * @param Map<String, String>
	 * @return Reader
	 * @throws ConnectionException
	 */
	private static Reader doPost(String url, Map<String, String> parameters) throws ConnectionException {
		try {
			HttpResponse httpResponse = requesPost(url, parameters);
			if (checkCodeReturn(httpResponse, url)) {
				HttpEntity httpEntity = httpResponse.getEntity();
				return new InputStreamReader(httpEntity.getContent());
			} else {
				throw new ConnectionException("<GenericHttp.doPost> Não foi possivel conectar ao servidor.");
			}
		} catch (IOException e) {
			Log.e(Constantes.LOG, e.getMessage(), e);
			throw new ConnectionException(String.format("<GenericHttp> Falha ao realizar uma requisição Get para url: %s", url), e);
		}
	}

	/**
	 * Metodo para fazer requisições GET
	 * 
	 * @param url
	 * @return HttpResponse
	 * @throws IOException
	 */
	private static HttpResponse requestGet(String url) throws ConnectionException {
		try {
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpGet httpGet = new HttpGet(url);
			return httpClient.execute(httpGet);
		} catch (IOException e) {
			Log.e(Constantes.LOG, e.getMessage(), e);
			throw new ConnectionException(String.format("<GenericHttp> Falha ao realizar uma requisição Get para url: %s", url), e);
		}
	}

	/**
	 * Metodo para fazer requisições POST
	 * 
	 * @param url
	 * @param Map
	 *            <String,String>
	 * @return HttpResponse
	 * @throws IOException
	 */
	private static HttpResponse requesPost(String url, Map<String, String> parameters) throws ConnectionException {
		try {
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpPost httpPost = new HttpPost(url);
			List<NameValuePair> params = getParams(parameters);
			httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
			return httpClient.execute(httpPost);
		} catch (IOException e) {
			Log.e(Constantes.LOG, e.getMessage(), e);
			throw new ConnectionException(String.format("<GenericHttp> Falha ao realizar uma requisição Post para url: %s", url), e);
		}
	}

	/**
	 * Mapear parametros para a requisição POST
	 * 
	 * @param map
	 * @return List<NameValuePair>
	 * @throws IOException
	 */
	private static List<NameValuePair> getParams(Map<String, String> map) {
		if (map == null || map.size() == 0) {
			return null;
		}
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		Iterator<String> e = (Iterator<String>) map.keySet().iterator();
		while (e.hasNext()) {
			String name = (String) e.next();
			Object value = map.get(name);
			params.add(new BasicNameValuePair(name, String.valueOf(value)));
		}
		return params;
	}

	/**
	 * Metodo para varificar codigo de retorno
	 * 
	 * @param HttpResponse
	 * @param url
	 * @return boolean
	 */
	private static boolean checkCodeReturn(HttpResponse httpResponse, String url) throws ConnectionException{
		final int statusCode = httpResponse.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			Log.w(Constantes.LOG, String.format("Error %d for URL %s", statusCode, url));
			return false;
		}
		return true;
	}
}
